/* Parse a configuration file into a struct using X-Macros */

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/utsname.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <modbus/modbus.h> // 引用libmodbus库
#include "utils.h"
#include "version.h"

// 自定义RTS控制函数
void custom_rs485_rts(modbus_t *ctx, int on)
{
	printf("\r\n\t%s...\r\n",on?"TX":"RX");
	fflush(stdout);
#ifdef SGWEC_BOARD
#else
    modgpio_setrs485out(on);
#endif
	usleep(100); 
}

int main(int argc, char *argv[])
{
	char portbuf[128];
	char bandbuf[128];
	char devidbuf[128];
	char fcodebuf[128];
	char regbuf[128];
	char countbuf[128];
	char regv_hexbuf[128];
	char regvbuf[128];

	if (CheckCmdLine(argc, argv, "h") || argc < 2)
	{
		printf("Uages:%s [-h] --port:<dev/ttySx> --band:<9600> --devid:<1> --fcode:<0x03> --reg:<0x0000> --regn:<1> [--regv:<FFFF>]\r\n",argv[0]);
		printf("\t\t--port:<dev/ttySx>\t\tRS485's device name,default is /dev/ttyS0.\r\n");
		printf("\t\t--band:<9600>\t\tBandrate for rs485\r\n");
		printf("\t\t--devid:<1>\t\tDevice id for modbus slave\r\n");
		printf("\t\t--fcode:<0x03>\t\tFunction code for modbus\r\n");
		printf("\t\t--reg:<0x0000>\t\tRegister address for modbus slave\r\n");
		printf("\t\t--regn:<1>\t\tWill read/write register count\r\n");
		printf("\t\t[--regv:<FFFF>]\t\tHex string for write register value list\r\n");
		return;
	}

	if (!GetCmdParamValue(argc, argv, "port", portbuf))
	{
		strcpy(portbuf,"/dev/ttyS0");
	}

	if (!GetCmdParamValue(argc, argv, "band", bandbuf))
	{
		strcpy(bandbuf,"9600");
	}

	if (!GetCmdParamValue(argc, argv, "devid", devidbuf))
	{
		strcpy(devidbuf,"0x01");
	}

	if (!GetCmdParamValue(argc, argv, "fcode", fcodebuf))
	{
		strcpy(fcodebuf,"0x03");
	}

	if (!GetCmdParamValue(argc, argv, "reg", regbuf))
	{
		strcpy(regbuf,"0x0000");
	}

	if (!GetCmdParamValue(argc, argv, "regn", countbuf))
	{
		strcpy(countbuf,"0x01");
	}

	if (!GetCmdParamValue(argc, argv, "regv", regv_hexbuf))
	{
		strcpy(regv_hexbuf,"00");
	}

    int ret;
	int band = StrToInt(bandbuf);
	unsigned char devid = StrToInt(devidbuf);
	unsigned char fcode = StrToInt(fcodebuf);
	unsigned int reg = StrToInt(regbuf);
	unsigned int regn = StrToInt(countbuf);
	unsigned char regv[64];
	int regvn = sizeof(regv);

    modbus_t *ctx = NULL;
    uint16_t value=0;

	memset(regv,0,sizeof(regv));
    HexDecode(regv_hexbuf,strlen(regv_hexbuf),regv,&regvn);

    // 创建一个RTU类型的容器
    ctx = modbus_new_rtu(portbuf, band, 'N', 8, 1);
		// 设置debug模式
	modbus_set_debug(ctx, 1);
	modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485);
    // 设置自定义RTS控制函数
    modbus_rtu_set_custom_rts(ctx, custom_rs485_rts);
	modbus_rtu_set_rts(ctx,MODBUS_RTU_RTS_UP);
	if(devid != 0xFF){
		//读取功率信息
		modbus_set_slave(ctx, devid);
		// RTU 模式下表示打开串口
		if (modbus_connect(ctx) == -1) {
			printf("Connection failed: %s \r\n", modbus_strerror(errno));
			modbus_free(ctx);
			return -1;
		}
		switch (fcode)
		{
		case 0x01:
			ret = modbus_read_bits(ctx,reg,regn,&regv[0]);
			if(ret == -1){
				printf("Read error (%s)\r\n", modbus_strerror(errno));
			}
			printf("RETURN:");
			for(int i=0;i<regn;i++){
				printf(" %02X",regv[i]);
			}
			printf("\r\n");
			break;
		case 0x02:
			ret = modbus_write_bits(ctx,reg,regn,&regv[0]);
			if(ret == -1){
				printf("Write error (%s)\r\n", modbus_strerror(errno));
			}
			printf("VALUE:");
			for(int i=0;i<regn;i++){
				printf(" %02X",regv[i]);
			}
			printf("\r\n");
			break;
		case 0x03:
			ret = modbus_read_registers(ctx,reg,regn,&regv);
			if(ret == -1){
				printf("Read error (%s)\r\n", modbus_strerror(errno));
			}
			printf("RETURN:");
			for(int i=0;i<regn*2;i++){
				printf(" %02X",regv[i]);
			}
			printf("\r\n");
			break;
		case 0x04:
			ret = modbus_write_registers(ctx,reg,regn,&regv);
			if(ret == -1){
				printf("Read error (%s)\r\n", modbus_strerror(errno));
			}
			printf("RETURN:");
			for(int i=0;i<regn*2;i++){
				printf(" %02X",regv[i]);
			}
			printf("\r\n");
			break;
		default:
			break;
		}
	}else{
		//扫描slave for devid
		int find=0;

		printf("Scaning device id...\r\n");
		for(devid = 0;devid < 0xFF;devid++){
			printf("0x%02X\r",devid);
			//读取功率信息
			modbus_set_slave(ctx, devid);
			// 设置debug模式
			modbus_set_debug(ctx, 1);
			// RTU 模式下表示打开串口
			if (modbus_connect(ctx) == -1) {
				printf("Connection failed: %s \r\n", modbus_strerror(errno));
				modbus_free(ctx);
				return -1;
			}
			switch (fcode)
			{
			case 0x01:
				ret = modbus_read_bits(ctx,reg,regn,&regv[0]);
				if(ret != -1){
					printf("RETURN:");
					for(int i=0;i<regn;i++){
						printf(" %02X",regv[i]);
					}
					printf("\r\n");
					find = 1;
				}
				break;
			case 0x02:
				ret = modbus_write_bits(ctx,reg,regn,&regv[0]);
				if(ret != -1){
					printf("RETURN:");
					for(int i=0;i<regn;i++){
						printf(" %02X",regv[i]);
					}
					printf("\r\n");
					find = 1;
				}
				break;
			case 0x03:
				ret = modbus_read_registers(ctx,reg,regn,&regv);
				if(ret != -1){
					printf("RETURN:");
					for(int i=0;i<regn*2;i++){
						printf(" %02X",regv[i]);
					}
					printf("\r\n");
					find = 1;
				}
				break;
			case 0x04:
				ret = modbus_write_registers(ctx,reg,regn,&regv);
				if(ret != -1){
					printf("RETURN:");
					for(int i=0;i<regn*2;i++){
						printf(" %02X",regv[i]);
					}
					printf("\r\n");
					find = 1;
				}
				break;
			default:
				break;
			}
			if(find)break;
		}
		if(devid != 0xFF)
			printf("\r\nFind device id is 0x%02X\r\n",devid);
		else
			printf("\r\nNot find device.\r\n");
	}
	// close the connection
	modbus_close(ctx);
	modbus_free(ctx);

	return 0;
}
